# ifndef __DbfFile_H_
# define __DbfFile_H_

# ifdef _MSC_VER
#	pragma pack (push, 1)
# endif

struct CFieldDesc {
	char  strName [11];
	BYTE  btType; // 'C' - string, 'N' - integer, 'L' - boolean, 'D' - date, 'M' - mark
	DWORD dwAddress;
	BYTE  btLen;
	BYTE  btDecOrdinal;
	WORD  wReserved0;
	BYTE  btWorkAreaID;
	WORD  wReserved1;
	BYTE  btSetFields;
	BYTE  baReserved [8];
};

struct CDbfHdr {
	BYTE btHasDbt; // 0x03 - no marks, 0x83 - have marks in .dbt

	BYTE btYear;
	BYTE btMonth;
	BYTE btDay;

	DWORD dwNumRecords;
	WORD wHdrSize;
	WORD wRecordSize;

	BYTE baReserved0 [3];
	BYTE baReserved1 [13];
	BYTE baReserved2 [4];

	CFieldDesc FieldDescriptors [1];
};

# ifdef _MSC_VER
#	pragma pack (pop)
# endif

# include "Wrappers.h"
# include "DatabaseTable.h"

class CDbfFile : public CDatabaseTable {
  public:
	CDbfFile (const char * _strFileName);
	~CDbfFile ();

	bool CantOpen () const {return m_pData == NULL;}

	virtual size_t GetFields () const {
		const CDbfHdr * const pHdr = reinterpret_cast<const CDbfHdr *> (m_pData);
		return (pHdr->wHdrSize - (sizeof (CDbfHdr) -  sizeof (CFieldDesc)))/sizeof (CFieldDesc);
	}

	virtual const char * GetFieldName (size_t _cField) const {
		const CDbfHdr * const pHdr = reinterpret_cast<const CDbfHdr *> (m_pData);
		return pHdr->FieldDescriptors [_cField].strName;
	}

	size_t GetFieldLength (size_t _cField) const {
		const CDbfHdr * const pHdr = reinterpret_cast<const CDbfHdr *> (m_pData);
		return pHdr->FieldDescriptors [_cField].btLen;
	}

	virtual size_t GetFieldMaxLength (size_t _cRecord, size_t _cField) const {
		return GetFieldLength (_cField);
	}

	const char * GetRawField (size_t _cRecord, size_t _cField) const {
		assert (_cField < m_vecFieldOffsets.size ());
		return m_pRecords + _cRecord*m_cRecordSize + m_vecFieldOffsets [_cField] + 1;
	}

	virtual size_t GetFieldS (size_t _cRecord, size_t _cField, char * _buf) const {
		const size_t cFieldLen = GetFieldLength (_cField);
		::strncpy (_buf, GetRawField (_cRecord, _cField), cFieldLen);
		_buf [cFieldLen] = '\0';
		// Cut ending spaces.
		char * p;
		for (p = _buf + cFieldLen - 1; p >= _buf; -- p)
			if (* p == ' ')
				* p = '\0';
			else
				break;

		return p - _buf + 1;
	}

	int GetFieldN (size_t _cRecord, size_t _cField) const;

	virtual size_t GetRecords () const {return m_cRecords;}

	virtual bool RecordExists (size_t _cRecord) const {
		if (_cRecord >= m_cRecords)
			return false;
		return m_pRecords [_cRecord*m_cRecordSize] != '*';
	}

  private:
	CFileForRead m_hFile;
	CWinHandle m_hFileMapping;
	const char * m_pData;
	size_t m_cSize;

	const char * m_pRecords;
	size_t m_cRecordSize;
	size_t m_cRecords;

	std::vector<size_t> m_vecFieldOffsets;
};


# endif // __DbfFile_H_